package com.boardour.socket.server;

import android.text.TextUtils;
import android.util.Log;

import com.boardour.socket.bean.ParamsData;
import com.boardour.socket.client.TCPClient;
import com.boardour.socket.foo.constants.TCPConstants;
import com.boardour.socket.foo.handle.ConnectorHandler;
import com.boardour.socket.foo.handle.OnReceivedPacketListener;
import com.boardour.socket.listener.OnReceiveListener;
import com.boardour.socket.listener.OnReceivedJsonListener;
import com.google.gson.Gson;

import net.qiujuer.library.clink.box.BytesReceivePacket;
import net.qiujuer.library.clink.box.StringReceivePacket;
import net.qiujuer.library.clink.core.Connector;
import net.qiujuer.library.clink.core.IoContext;
import net.qiujuer.library.clink.core.Packet;
import net.qiujuer.library.clink.core.ReceivePacket;
import net.qiujuer.library.clink.impl.IoSelectorProvider;
import net.qiujuer.library.clink.impl.SchedulerImpl;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 服务端
 */
public class TCPServerPresenter implements Runnable, TCPClient.ConnectorStatusListener, OnReceivedPacketListener {
    private OnReceiveListener onReceiveListener;
    private OnReceivedJsonListener onReceivedJsonListener;
    private TCPServer tcpServer;
    private AtomicBoolean isStarting = new AtomicBoolean(false);
    private Gson mGson = new Gson();
    private int port = -1;


    public void start() {
        start(TCPConstants.PORT_SERVER);
    }

    public void start(int port) {
        this.port = port;
        if (isStarting.compareAndSet(false, true)) {
            Executors.newSingleThreadExecutor().execute(this);
        }
    }

    public boolean isStart() {
        return isStarting.get();
    }

    public void setOnReceiveListener(OnReceiveListener onReceiveListener) {
        this.onReceiveListener = onReceiveListener;
    }

    @Override
    public void run() {
        try {
            IoContext.setup()
                    .ioProvider(new IoSelectorProvider())
                    .scheduler(new SchedulerImpl(4))
                    .start();
            tcpServer = new TCPServer(port);
            tcpServer.setOnReceiveListener(TCPServerPresenter.this);
            boolean isSucceed = tcpServer.start();

            Log.e("Server", "Start TCP server isSucceed:"+isSucceed);
            if (!isSucceed) {
                Log.e("Server", "Start TCP server failed!");
                close();
            }
            // 这里要注册个
        } catch (Exception e) {
            e.printStackTrace();
            close();
            Log.e("Server", "Start TCP server failed! " + e.getMessage());
        }

    }

    @Override
    public void onConnectorClosed(Connector connector) {
        close();
    }

    public void close() {
        isStarting.set(false);
        try {
            if (tcpServer != null) {
                tcpServer.stop();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            IoContext.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        tcpServer = null;
        onReceivedJsonListener = null;
        onReceiveListener = null;
    }


    private void parseData(byte[] data, SocketChannel channel) {
        try {
            // 2. 解析头
            ByteBuffer headBuffer = ByteBuffer.allocate(16);
            headBuffer.put(data, 0, 16);
            headBuffer.flip();
            int trackIndex = headBuffer.getInt();
            long presentationTimeUs = headBuffer.getLong();
            int length = headBuffer.getInt();

            // 3. 拿到实际数据
            ByteBuffer dataBuffer = ByteBuffer.allocate(length);
            dataBuffer.put(data, 16, length);
            dataBuffer.flip();

            onReceiveListener.onReceive(trackIndex, dataBuffer.array(), presentationTimeUs, channel);

        } catch (Throwable e) {
            e.printStackTrace();
            Log.e("TAG", e.getMessage() + "");
        }
    }

    /**
     * 发送Json数据
     */
    public void send(String json) {
        if (tcpServer == null || TextUtils.isEmpty(json)) {
            return;
        }
        // 这里是可以发送数据的
        ConnectorHandler connector = getConnector();
        if (connector != null) {
            connector.send(json);
        }
    }

    public <T> void send(ParamsData<T> data) {
        if (tcpServer == null || data == null) {
            return;
        }
        // 这里是可以发送数据的
        ConnectorHandler connector = getConnector();
        if (connector != null) {
            connector.send(mGson.toJson(data));
        }
    }

    public ConnectorHandler getConnector() {
        if (tcpServer == null) {
            return null;
        }
        return tcpServer.getConnector();
    }

    private SocketChannel getChannel() {
        ConnectorHandler connector = getConnector();
        if (connector != null) {
            return connector.getChannel();
        }
        return null;
    }

    public String getIp() {
        SocketChannel channel = getChannel();
        if (channel != null) {
            String ip = channel.toString();
            ip = ip.substring(ip.lastIndexOf('/') + 1, ip.lastIndexOf(":"));
            return ip;
        }
        return null;

    }

    /**
     * 接收到数据的回调
     *
     * @param packet
     */
    @Override
    public void onReceivedPacket(ReceivePacket packet, SocketChannel channel) {
        if (packet.type() == Packet.TYPE_MEMORY_BYTES) {
            if (onReceiveListener == null) {
                return;
            }
            // 1. 拿到数据
            BytesReceivePacket bytesPacket = (BytesReceivePacket) packet;
            final byte[] data = bytesPacket.entity();
            parseData(data, channel);
        } else if (packet.type() == Packet.TYPE_MEMORY_STRING) {
            if (onReceivedJsonListener != null) {
                String json = ((StringReceivePacket) (packet)).entity();
                onReceivedJsonListener.onReceivedJson(json, channel);
            }
        }
    }

    public void setOnReceivedJsonListener(OnReceivedJsonListener onReceivedJsonListener) {
        this.onReceivedJsonListener = onReceivedJsonListener;
    }
}
